﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace LevSTProgramTransform
{
    public class HEXLineStructure
    {
        //////////////////////////////////////////////////////////////////////
        // write Hex File
        // : 10　0000　00　020003787FE4F6D8FD75812B02004A02　D6
        // : 20  1000  00  3EE4C7BC3E7E33433D86CD9C3F9EE00902030405FEFC00C80000000000000000 37
        //1　2　　 3  4   5 　                              6
        // 1) HEX 檔的啟始格式
        // 2) 兩碼(10H)所代表的是該列總共具備多少個Bytes 的資料, 應該有16 個Bytes
        // 3) 四碼所代表的是放置資料的啟始位置
        // 4) 兩碼是檢查碼，所代表的是該列有無資料存放，若有則為00H，若無則為01H
        // 5) 資料存放區，總共32 碼16 個Bytes
        // 6) Checksum 值
        ///////////////////////////////////////////////////////////////////////   

        //public byte DataLength;
        public UInt16 Address;
        public byte CheckCode = 0;
        public byte[] HexData;

        public HEXLineStructure()
        {
        }
        public HEXLineStructure(UInt16 address, byte[] data, byte checkCode)
        {
            Address = address;
            HexData = data;
            CheckCode = checkCode;
        }
        public bool isAddressInRange(UInt16 address)
        {
            if ((address >= Address) && (address < (Address + HexData.Length)))
            {
                return true;
            }
            return false;
        }
        public bool setHexStringLine(string HexLine)
        {
            string str = HexLine.Replace(':', ' ').Trim();
            byte[] hexByte = MassUtilityClass.HexStringToByteArray(str);
            byte length = hexByte[0];
            if ((length + 5) != hexByte.Length)
            {
                //fail
                length = 0;
                return false;
            }
            //UInt16 address = BitConverter.ToUInt16(hexByte, 1);
            UInt16 address = hexByte[1];
            address = (UInt16)((address * 256) + hexByte[2]);
            //byte[] add = BitConverter.GetBytes(address);
            byte checkCode = hexByte[3];
            byte[] data = new byte[length];
            Array.Copy(hexByte, 4, data, 0, length);
            byte ChkSum8 = hexByte[hexByte.Length - 1];

            byte[] computeChkSumData = new byte[hexByte.Length - 1];
            Array.Copy(hexByte, 0, computeChkSumData, 0, computeChkSumData.Length);
            byte computeChdSum = MassUtilityClass.CalculateHexChecksum8(computeChkSumData);
            if (ChkSum8 != computeChdSum)
            {
                return false;
            }
            Address = address;
            CheckCode = checkCode;
            HexData = data;
            return true;
        }
        public bool setDataByAddress(UInt16 address, byte[] data)
        {
            if (isAddressInRange(address))
            {
                int offset = address - Address;
                return setDataByOffset(offset, data);
            }
            return false;
        }
        public bool setDataByOffset(int DataOffsetIndex, byte[] data)
        {
            if ((DataOffsetIndex >= HexData.Length) || (DataOffsetIndex + data.Length) > HexData.Length)
            {
                return false;
            }
            int idx2 = DataOffsetIndex;
            for (int idx = 0; idx < data.Length; idx++)
            {
                HexData[idx2++] = data[idx];
            }
            return true;
        }
        public string getHexStructureLine()
        {
            List<byte> hexLine = new List<byte>();
            string hexStructureLine = ":";
            hexLine.Add((byte)HexData.Length);
            byte[] add = BitConverter.GetBytes(Address);
            hexLine.Add(add[1]);
            hexLine.Add(add[0]);
            hexLine.Add(CheckCode);
            hexLine.AddRange(HexData);
            byte[] computeChkSumData = hexLine.ToArray();
            byte computeChdSum = MassUtilityClass.CalculateHexChecksum8(computeChkSumData);
            hexLine.Add(computeChdSum);
            computeChkSumData = hexLine.ToArray();
            hexStructureLine += MassUtilityClass.ByteArrayToHexString(computeChkSumData, false);
            return hexStructureLine;
        }
    }



    class HexFileDocument
    {
        string HexFileName = string.Empty;
        bool HexFileOpened = false;
        List<HEXLineStructure> HEXLineStructureList;
        StreamWriter stWriter;
        public HexFileDocument()
        {
        }
        public bool openHexFile(string fileName)
        {
            HexFileName = fileName;
            bool returnFlag = false;
            if (!(File.Exists(HexFileName)))
            {
                Console.WriteLine("Could not find File : " + HexFileName);
                return returnFlag;
            }
            bool flag1, flag2;
            string readLineStr;
            FileStream fsFile = null;
            StreamReader srReader = null;
            HEXLineStructureList = new List<HEXLineStructure>();
            try
            {
                fsFile = new FileStream(HexFileName, FileMode.Open);
                /*
                 * 讀取數據最簡單的方法是Read()。此方法將流的下一個字符作為正整數值返回，
                 * 如果達到了流的結尾處，則返回-1。
                 */
                srReader = new StreamReader(fsFile, Encoding.Default);

                ////////////////////////////////////////////////////////////////////////
                //Continue to read until you reach end of file
                while (srReader.Peek() >= 0)
                {
                    readLineStr = srReader.ReadLine();
                    //readLineStr = readLineStr.ToUpper();
                    HEXLineStructure hLS = new HEXLineStructure();
                    flag2 = hLS.setHexStringLine(readLineStr);
                    //flag1 = hLS.setData(0x1e, new byte[] { 0x22, 0x55 });
                    //string s = hLS.getHexStructureLine();
                    if (flag2)
                    {
                        HEXLineStructureList.Add(hLS);
                    }
                }//while (srReader.Peek() >= 0)
                srReader.Close();
                fsFile.Close();
                returnFlag = true;
                HexFileOpened = true;
                return returnFlag;
            }
            catch (Exception excep)
            {
                Console.WriteLine("檔案開啟錯誤 : " + HexFileName);
                Console.WriteLine("  : " + excep);
                if (fsFile != null)
                {
                    fsFile.Close();
                }
                returnFlag = false;
                //throw excep;
            }
            finally
            {
                if (fsFile != null)
                {
                    fsFile.Close();
                }
            }
            return false;
        }

        public void setHexData(UInt16 address, byte[] data)
        {
            if (!HexFileOpened)
            {
                return;
            }
            foreach (HEXLineStructure hls in HEXLineStructureList)
            {
                if (hls.isAddressInRange(address))
                {
                    hls.setDataByAddress(address, data);
                }
            }
        }
        public void SaveHexFile(string fileName)
        {
            if (!HexFileOpened)
            {
                return;
            }
            try
            {
                //write header file 
                stWriter = new StreamWriter(fileName);
                foreach (HEXLineStructure hls in HEXLineStructureList)
                {
                    stWriter.WriteLine(hls.getHexStructureLine());
                }
                stWriter.Close();
            }
            catch (Exception excep)
            {
                Console.WriteLine("檔案開啟錯誤 : " + fileName);
                Console.WriteLine("  : " + excep);
                if (stWriter != null)
                {
                    stWriter.Close();
                }
                //throw excep;
            }
            finally
            {
                //write header file 
                stWriter = new StreamWriter(@".\Log\_Temp_" + DateTime.Now.ToString("yyyyMMdd_HHmmss_") + ".hex");
                foreach (HEXLineStructure hls in HEXLineStructureList)
                {
                    stWriter.WriteLine(hls.getHexStructureLine());
                }
                stWriter.Close();

                //if (stWriter != null)
                //{
                //    stWriter.Close();
                //}
            }
        }//public void Save_Pasered_Header_File()


    }
}
